#pragma once

#include <iostream>
#include <string>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <functional>

#include "Log.hpp"
#include "Socket.hpp"
#include "InetAddr.hpp"

using namespace socket_ns;
using http_t = std::function<std::string(std::string request)>;

class TcpServer;
class ThreadData
{
public:
    ThreadData(socket_sprt fd, InetAddr client, TcpServer *ts) : _fd(fd), _client(client), _ts(ts)
    {
    }

public:
    socket_sprt _fd;
    InetAddr _client;
    TcpServer *_ts;
};
class TcpServer
{
public:
    TcpServer(int port, http_t service)
        : _localaddr("0", port), _listenfd(std::make_unique<TcpSocket>()), _http_service(service), _isrunning(false)
    {
        _listenfd->BuildListenSocket(_localaddr);
    }

    ~TcpServer()
    {
    }

    static void *HandleSock(void *arg) // 设置为static 保证参数没有this指针
    {
        pthread_detach(pthread_self());
        //std::cout << "tid:" << gettid() << std::endl;
        ThreadData *td = static_cast<ThreadData *>(arg);

        std::string request;
        // 多数情况下，读取的是一个完整的请求，暂时不对请求添加报头
        ssize_t n = td->_fd->Recv(&request);    // 读取请求
        if (n > 0)
        {
            std::string response = td->_ts->_http_service(request);
            td->_fd->Send(response);            // 发送应答
        }

        td->_fd->Close();
        delete td; // client退出后，释放td
        return nullptr;
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 客户端网络信息
            InetAddr peer;
            // 创建一个套接字用于服务器与客户端进行通信
            socket_sprt normalsock = _listenfd->Accepter(&peer);

            // 多线程处理请求，主线程继续监听是否有新的客户端连接
            pthread_t t;
            ThreadData *td = new ThreadData(normalsock, InetAddr(peer), this);
            pthread_create(&t, nullptr, HandleSock, td);
        }
        _isrunning = false;
    }

private:
    std::unique_ptr<Socket> _listenfd;
    InetAddr _localaddr; // 服务器网络地址
    bool _isrunning;
    http_t _http_service; // 回调函数
};